package utils

import (
	"errors"
	"github.com/cy77cc/hioshop/global"
	"github.com/golang-jwt/jwt/v4"
	"time"
)

// MyClaims Id为微信openid
type MyClaims struct {
	Id uint `json:"id"`
	jwt.RegisteredClaims
}

// 常量
var (
	ErrTokenExpired     = errors.New("Token is expired")
	ErrTokenInvalid     = errors.New("Token is invalid")
	ErrTokenMalformed   = errors.New("Token is malformed")
	ErrTokenNotValidYet = errors.New("Token is not valid yet")
	ErrTokenNotValidId  = errors.New("Token is not valid id")
	ErrTokenSignature   = errors.New("Token signature is invalid")
	MySecret            = []byte(global.CONFIG.System.SecretKey)
)

const TokenExpireDuration = time.Hour * 24 * 10

// GenToken 使用hsa256加密生成token, 传递weixinopenid
func GenToken(id uint) (string, error) {
	c := MyClaims{
		id,
		jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(TokenExpireDuration)),
			Issuer:    "hioshop",
		},
	}
	// 指定加密方式
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
	// 使用密钥加密
	return token.SignedString(MySecret)
}

// ParseToken 解析token
func ParseToken(tokenString string) (*MyClaims, error) {
	token, err := jwt.ParseWithClaims(
		tokenString,
		&MyClaims{},
		func(token *jwt.Token) (interface{}, error) {
			return MySecret, nil
		},
	)

	if err != nil {
		if ve, ok := err.(*jwt.ValidationError); ok {
			// 不能正确验证token
			if ve.Errors&jwt.ValidationErrorMalformed != 0 {
				return nil, ErrTokenMalformed
				// token已经过期
			} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
				return nil, ErrTokenExpired
			} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
				return nil, ErrTokenNotValidYet
			} else {
				return nil, ErrTokenInvalid
			}
		}
	}
	if claims, ok := token.Claims.(*MyClaims); ok && token.Valid {
		return claims, nil
	}
	return nil, ErrTokenInvalid
}

// RefreshToken 刷新token
func RefreshToken(id uint) (string, error) {
	token, err := GenToken(id)
	if err != nil {
		return "", err
	}
	return token, nil
}
